package com.kaifamiao.wendao.controller;

import com.kaifamiao.wendao.entity.Customer;
import com.kaifamiao.wendao.entity.Topic;
import com.kaifamiao.wendao.service.CustomerService;
import com.kaifamiao.wendao.service.TopicService;
import com.kaifamiao.wendao.utils.Constants;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.tinylog.Logger;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;

@WebServlet("/customer/*")
public class CustomerServlet extends HttpServlet {

    private TopicService topicService;

    private CustomerService customerService;

    @Override
    public void init() throws ServletException {
        customerService = new CustomerService();
        topicService = new TopicService();
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String method = request.getMethod();
        String uri = request.getRequestURI();
        // GET "/customer/sign/up"
        if ("GET".equals(method) && uri.endsWith("/sign/up")){
            this.signUpPage(request, response);
            return;
        }
        // POST "/customer/sign/up"
        if("POST".equals(method) && uri.endsWith("/sign/up")) {
            this.signUpAction(request, response);
            return;
        }
        // GET "/customer/sign/in"
        if ("GET".equals(method) && uri.endsWith("/sign/in")){
            this.signInPage(request, response);
            return;
        }
        // POST "/customer/sign/in"
        if("POST".equals(method) && uri.endsWith("/sign/in")) {
            this.signInAction(request, response);
            return;
        }

        // GET "/customer/sign/out"
        if("GET".equals(method) && uri.endsWith("/sign/out")) {
            this.signOutAction(request, response);
            return;
        }

        // GET "/customer/change"
        if("GET".equals(method) && uri.endsWith("/customer/change")) {
            this.changePage(request, response);
           return;
        }
        // POST "/customer/change"
        if("POST".equals(method) && uri.endsWith("/customer/change")) {
            this.changeAction(request, response);
            return;
        }
        // GET "/customer/view"
        if("GET".equals(method) && uri.endsWith("/view")) {
            this.viewPage(request, response);
            return;
        }
        // GET "/customer/sign/remove注销"
        if("GET".equals(method) && uri.endsWith("/sign/remove")) {
            this.removePage(request, response);
            return;
        }
        // GET "/customer/sign/remove注销"
        if("POST".equals(method) && uri.endsWith("/sign/remove")) {
            this.removeAction(request, response);
            return;
        }
        //GET"/customer/sign/setting"修改昵称
        if( "GET".equals( method ) && uri.endsWith("/sign/setting") ) {
            this.settingPage(request, response);
            return;
        }
        //POST"/customer/sign/setting"修改昵称
        if( "POST".equals( method ) && uri.endsWith("/sign/setting") ) {
            this.settingAction(request, response);
            return;
        }
        if("GET".equals(method) && uri.endsWith("/views")) {
            this.viewPageUser(request, response);
            return;
        }
   }

    // GET "/customer/sign/up"
    protected void signUpPage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        String path = "/WEB-INF/pages/customer/sign-up.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request,response);
    }

    private boolean validateSignUp(HttpServletRequest request)
            throws ServletException, IOException {

        HttpSession session = request.getSession();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String nickname = request.getParameter("nickname");
        session.setAttribute("nickname", nickname);
        String confirm = request.getParameter("confirm");


        // 检查用户名是否为空
        if (StringUtils.isEmpty(username) || StringUtils.isBlank(username)){
            session.setAttribute("message","用户名不能为空");
            return false;
        }
        // 检查密码是否为空
        if (StringUtils.isEmpty(password) || StringUtils.isBlank(username)){
            session.setAttribute("username",username);
            session.setAttribute("message","密码不能为空");
            return false;
        }
        // 检查两次输入密码是否一致
        if (!StringUtils.equals(password,confirm)){
            session.setAttribute("username",username);
            session.setAttribute("message","两次密码输入不一致");
            return false;
        }
        //获取生成的验证码
        String captcha = request.getParameter("captcha");
        // 检查验证码是否为空
        if (StringUtils.isBlank(captcha) || StringUtils.isEmpty(captcha)){
            session.setAttribute("captcha",captcha);
            session.setAttribute("message","验证码不能为空");
            return false;
        }
        // 检查验证码与会话中存储的CAPTCHA属性值是否相等
        //从会话中获取验证码
        String code = (String) session.getAttribute("CAPTCHA");
        if (!StringUtils.equalsIgnoreCase(code,captcha)){
            session.setAttribute("username",username);
            session.setAttribute("message","你输入的验证码不正确");
            return false;
        }
        // 检查用户名是否被占用(需要去数据库检查)
        if (customerService.load(username)){
            session.setAttribute("username",username);
            session.setAttribute("message","用户名已经被占用");
            return false;
        }
        // 以上检查皆通过后即可返回 true ，以准予下一步操作
        return true;
    }

    // POST "/customer/sign/up"
    protected void signUpAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();
        //数据校验
        if (this.validateSignUp(request)) {
            //创建Customer实例
            Customer c = new Customer();
            try {
                //将请求对象中的参数值填充到Customer实例中
                BeanUtils.populate(c, request.getParameterMap());
            } catch (Exception e) {
                //将提示信息设置到会话属性中
                session.setAttribute("message", "服务器内部错误: 数据收集失败");
                Logger.error(e);
            }

            try {
                // 执行保存操作并判断是否保存成功
                if (customerService.save(c)) {
                    Logger.trace("保存成功:{}", c);
                    session.setAttribute("message", "注册成功");
                    //保存成功时重定向到登录页面
                    response.sendRedirect(request.getContentType() + "/customer/sign/in");
                    return;
                }
                session.setAttribute("message", "注册失败");
                session.setAttribute("username", c.getUsername());
            }
            //若save方法执行时发生异常
            catch (Exception e) {
                session.setAttribute("message","注册失败"+e.getMessage());
                session.setAttribute("username",c.getUsername());
                Logger.error(e);
            }
        }
        // 当数据校验失败或保存失败则重定向到注册页面
        response.sendRedirect(request.getContextPath() + "/customer/sign/up");
    }
    // GET "/customer/sign/in"
    protected void signInPage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        String path = "/WEB-INF/pages/customer/sign-in.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
    }

    private boolean validateSignIn(HttpServletRequest request)
            throws ServletException, IOException{
        HttpSession session = request.getSession();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String captcha = request.getParameter("captcha");
        // 登录名称是否为空
        if (StringUtils.isBlank(username) || StringUtils.isEmpty(username)){
            session.setAttribute("message","登录名称不能为空");
            return false;
        }
        // 登录密码是否为空
        if (StringUtils.isBlank(password) || StringUtils.isEmpty(password)){
            session.setAttribute("username",username);
            session.setAttribute("message","密码不能为空");
            return false;
        }
        // 验证码是否为空
        if (StringUtils.isBlank(captcha) || StringUtils.isEmpty(captcha)){
            session.setAttribute("username",username);
            session.setAttribute("message","验证码不能为空");
            return false;
        }
        // 验证码是否正确
        String code = (String)session.getAttribute("CAPTCHA");
        if (!StringUtils.equalsIgnoreCase(captcha,code)){
            session.setAttribute("username",username);
            session.setAttribute("message","验证码输入不正确，请重新输入");
            return false;
        }
        return true;

    }
    // POST"/customer/sign/in"
    protected void signInAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        HttpSession session = request.getSession();
        String username = request.getParameter("username");
        if(this.validateSignIn(request)) {
            // 根据登录名称查询用户信息
            Customer c = customerService.loadName(username);
            // 检查登录名称是否错误(根据登录名称查询后返回null则表示登录名称错误)
            if (c == null) {
                session.setAttribute("username", username);
                session.setAttribute("message", "登录名称错误，请重新输入");
                response.sendRedirect(request.getContextPath() + "/customer/sign/in");
                return;
            }

            // 获得用户在表单上输入的原始密码
            final String password = request.getParameter("password");
            String encrypted = customerService.encrypt(password, c.getSalt());
            String dbpasswd = c.getPassword();

            // 检查登录密码是否【不正确】
            if (!StringUtils.equals(encrypted, dbpasswd)) {
                session.setAttribute("username", username);
                session.setAttribute("message", "登录密码错误，请重新输入");
                response.sendRedirect(request.getContextPath() + "/customer/sign/in");
                return;
            }

            // 将用户对象设置到会话属性中
            session.setAttribute(Constants.CUSTOMER_LOGINED, c);
            response.sendRedirect(request.getContextPath() + "/index.jsp");
        }
        response.sendRedirect(request.getContextPath() + "/customer/sign/in");
        return;
    }

    // GET "/customer/sign/out"
    protected void signOutAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();
        session.removeAttribute(Constants.CUSTOMER_LOGINED);
        response.sendRedirect( request.getContextPath() + "/index.jsp" );
    }

    // GET "/customer/change"
    protected void changePage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        String path = "/WEB-INF/pages/customer/change.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
    }

    private boolean validateChange(HttpServletRequest request) throws ServletException, IOException {
        String original = request.getParameter("original");
        String password = request.getParameter("password");
        String confirm = request.getParameter("confirm");
        String captcha = request.getParameter("captcha");
        HttpSession session = request.getSession();

        if (StringUtils.isBlank(original) || StringUtils.isEmpty(original)){
            session.setAttribute("message","必须输入原始密码");
            return false;
        }

        if (StringUtils.isEmpty(password) || StringUtils.isBlank(password)){
            session.setAttribute("message","请输入新密码");
            return false;
        }
        if (!StringUtils.equals(password,confirm)){
            session.setAttribute("message","两次密码输入错误");
            return false;
        }
        // 验证码是否为空
        if (StringUtils.isBlank(captcha) || StringUtils.isEmpty(captcha)){
            session.setAttribute("message","验证码不能为空");
            return false;
        }
        // 验证码是否正确
        String code = (String)session.getAttribute("CAPTCHA");
        if (!StringUtils.equalsIgnoreCase(captcha,code)){
            session.setAttribute("message","验证码输入不正确，请重新输入");
            return false;
        }

        Customer c = (Customer) session.getAttribute("customer");

        // 获得用户在表单上输入的原始密码
        String encrypted = customerService.encrypt(original, c.getSalt());
        String dbpasswd = c.getPassword();

        // 检查登录密码是否【不正确】
        if (!StringUtils.equals(encrypted, dbpasswd)) {
            session.setAttribute("message", "登录密码错误，请重新输入");
            return false;
        }
        return true;
    }
    // POST "/customer/change"
    protected void changeAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        HttpSession session = request.getSession();
        if(this.validateChange(request)){

            // 获得用户在表单中填写的原始密码
            String password = request.getParameter("password");
            // 根据用户查询用户数据
            Customer c = (Customer)session.getAttribute("customer");
            // 对用户输入的密码进行加密
            String encrypted = customerService.encrypt(password,c.getSalt());
            // 修改用户数据
            c.setPassword(encrypted);
            // 更新用户信息
            customerService.update(c);
            response.sendRedirect(request.getContextPath() + "/customer/sign/in");
            return;
        }
        response.sendRedirect(request.getContextPath() + "/customer/change");
        }

    // GET "/customer/view"
    protected void viewPage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        HttpSession session = request.getSession();
        Customer c = (Customer) session.getAttribute("customer");
        // 查询所有的话题
        List<Topic> topic = topicService.findView(c.getId());
        // 将查询到的话题列表设置到请求属性中(将来可以在JSP中通过EL表达式来获取)

        request.setAttribute("now",LocalDate.now());
        request.setAttribute("regDate",c.getRegisterDate());
        //计算注册天数
        LocalDate localDate = LocalDate.now();
        LocalDate regDate = c.getRegisterDate();
        long l =localDate.getDayOfYear()-regDate.getDayOfYear();
        request.setAttribute("date",l);

        request.setAttribute("now",LocalDate.now());

//      查询发帖量
        Long count = topicService.loadCountTitle(c.getId());
        request.setAttribute("count",count);


        request.setAttribute("topicList", topic);
        String path = "/WEB-INF/pages/customer/view.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);

    }
    //注销账户
    protected void removePage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String path = "/WEB-INF/pages/customer/remove.jsp";
        RequestDispatcher rd = request.getRequestDispatcher(path);
        rd.forward(request, response);
    }
    //注销验证
    private boolean removeChange(HttpServletRequest request) throws ServletException, IOException {
        String id = request.getParameter("id");
        System.out.println(id);
        String original = request.getParameter("original");
        System.out.println(original);
        HttpSession session = request.getSession();
        if(StringUtils.isEmpty(original) || StringUtils.isBlank(original)) {
            session.setAttribute("message", "必须输入原始密码");
            return false;
        }
        //查询id并上传到请求中
        Customer c = customerService.load(Long.valueOf(id));
        request.setAttribute("targetCustomer", c );
        // 对用户输入的原始密码进行加密
        String encrypted = customerService.encrypt(original, c.getSalt());
        // 对用户输入的原始密码加密后再与数据库中存储的密码比较
        if( !StringUtils.equals(encrypted, c.getPassword())) {
            session.setAttribute("message", "你输入的原始密码不正确");
            return false;
        }

        return true;
    }
    //注销
    private void removeAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String id = request.getParameter("id");

        if(Objects.isNull(id)) {
            response.sendRedirect(request.getContextPath()+ "/customer/list");
            return;
        }
        if(this.removeChange(request)){
            Long lid = Long.valueOf(id);
            customerService.removeCustomer(lid);
            response.sendRedirect(request.getContextPath() + "/customer/sign/in");
            HttpSession session = request.getSession();
            session.setAttribute("message", "注销成功");
            return;
        }
        String path = "/WEB-INF/pages/customer/remove.jsp";
        RequestDispatcher rd = request.getRequestDispatcher(path);
        rd.forward(request, response);

    }

    //修改昵称
    //GET"/customer/sign/setting"
    protected void settingPage(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String path = "/WEB-INF/pages/customer/sign-setting.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
    }

    protected boolean validateSetting(HttpServletRequest request)
            throws ServletException, IOException {

        HttpSession session=request.getSession();
        String username=request.getParameter("username");
        String nickname=request.getParameter("nickname");
        String captcha=request.getParameter("captcha");
        String code=(String) session.getAttribute("CAPTCHA");

        if (StringUtils.isEmpty(nickname) && StringUtils.isBlank(nickname)){
            session.setAttribute("username",username);
            session.setAttribute("message","请输入昵称");
            return false;
        }
        // 验证码是否为空
        if (StringUtils.isEmpty(captcha) || StringUtils.isBlank(captcha)){
            session.setAttribute("message","验证码不能为空");
            return false;
        }
        // 验证码是否正确
        if (!StringUtils.equalsIgnoreCase(code,captcha)){
            session.setAttribute("message","验证码不正确");
            return false;
        }
        return true;
    }


    //修改昵称
    //POST"/customer/sign/setting"
    protected void settingAction(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();
        if (this.validateSetting(request)){
            String nickname=request.getParameter("nickname");
            // 根据用户编号查询用户数据
            Customer c = (Customer)session.getAttribute("customer");
            // 修改用户数据
            c.setNickname( nickname );
            // 更新用户信息
            customerService.update(c);
            response.sendRedirect(request.getContextPath()+"/topic/list");
            return;
        }
        response.sendRedirect(request.getContextPath()+"/customer/sign/setting");
    }


    protected void viewPageUser(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException{
        String idString=request.getParameter("id");
        System.out.println(idString);
        Long id=Long.valueOf(idString);
        Topic t=topicService.find(id);
        System.out.println(t);
        request.setAttribute("topic",t);

        Customer customer=t.getAuthor();
        //计算注册天数
        LocalDate localDate = LocalDate.now();
        LocalDate regDate = customer.getRegisterDate();
        long l =localDate.getDayOfYear()-regDate.getDayOfYear();
        request.setAttribute("date",l);

        Long count = topicService.loadCountTitle(customer.getId());
        request.setAttribute("count",count);


        String path = "/WEB-INF/pages/customer/views.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
    }
}
